
struct Structure(i32);

use std::fmt;
impl fmt::Display for Structure {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "call this override function: {}", self.0)
    }
}

fn print(){
    println!("Structure is: {}", Structure(1));
}

#[derive(Debug)]
struct MinMax(i64, i64);

impl fmt::Display for MinMax {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "({}, {})", self.0, self.1)
    }
}

#[derive(Debug)]
struct Point2D {
    x: f64,
    y: f64,
}
impl fmt::Display for Point2D {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "x: {}, y: {}", self.x, self.y)
    }
}

fn print_struct(){
    let minmax = MinMax(0, 14);
    println!("Compare structures:");
    println!("Display: {}", minmax);
    println!("Debug: {:?}", minmax);

    let big = MinMax(-300, 300);
    let small = MinMax(-3, 3);

    println!("The big range is {big}, and the small is {small}");

    let point = Point2D{x: 3.3, y: 7.2 };
    println!("Compare points:");
    println!("Display: {}", point);
    println!("Debug: {:?}", point);
}

struct List(Vec<i32>);
impl fmt::Display for List {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let vec = &self.0;
        write!(f, "[")?; //TODO: details ??

        for (count, v) in vec.iter().enumerate(){
            if count != 0 {
                write!(f, ", ")?; //TODO: details
            }
            write!(f, "{}", v)?; //TODO: details
        }
        write!(f, "]")
    }
}
fn print_list(){
    let l = List(vec![1, 2, 3]);
    println!("struct List(Vec<i32>): {}", l);
}

// Result return with -[?]
// enum Result<T, E> {
//  Ok(T),
//  Err(E),
// }
//pub fn open<P: AsRef<Path>>(path: P) -> Result<File>; 
//pub type Result<T> = Result<T, Error>; //Error std::io::Error
use std::fs::File;
use std::io::{Read, self};

/*
fn print_type_of<T>(_: &T){
    println!("{}", std::any::type_name::<T>());
}*/
fn file_ops_match()->Result<String, io::Error>{
    let res = File::open("hello.txt");
    let mut f = match res {
        Ok(file) => file, 
        Err(e) => return Err(e),
    };

    let mut s = String::new();
    match f.read_to_string(&mut s) {
        Ok(_) => Ok(s),
        Err(e) => Err(e),
    }
}
fn file_ops_easy_match() -> Result<String, io::Error>{
    let mut f = File::open("hello.txt")?; //OK -> File; Failed: Result::Err(io::Error)
    let mut s = String::new();
    f.read_to_string(&mut s)?; // OK -> usize; Failed: Result::Err(io::Error)
    Ok(s) // Result::Ok(String)
}
fn file_operating() -> Result<String, io::Error>{
    file_ops_match()?;
    let s = file_ops_easy_match()?;
    Ok(s)
}

pub fn main(){
    println!("  >1.structure print:");
    print();

    println!("  >2.cusome structure print:");
    print_struct();

    println!("  >3.struct with List:");
    print_list();
    
    println!("  >4. file operating for use Result<File, io::Error>");
    // original statement
    /* let r = file_operating();
    match r {
        Ok(s) => println!("{}", s),
        _ => (),
    }*/

    // if let function
    let r = file_operating();
    if let Ok(s) = r {
        println!("read file ok, content: {}", s);
    }

}
